﻿/*  ----------------------------------------------------------------------------
 *  SysServer
 *  ----------------------------------------------------------------------------
 *  File:       TQueue.cs
 *  Creater:     SEEN\MistSeen
 *  ----------------------------------------------------------------------------
 *  $Date: 2010-09-06 10:36:01 +0000 (Mon, 06 Sep 2010) $
 *  $Rev: 15 $
 *  $Author: ScorDeity $
 *  $URL: http://sysserver.googlecode.com/svn/trunk/src/SysServer/Collections/TQueue.cs $
 *  $Id: TQueue.cs 15 2010-09-06 10:36:01Z ScorDeity $
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace SysServer.Collections
{
    /// <summary>
    /// 无锁队列中的每一个Item
    /// </summary>
    public class TQueueNode : TEntity
    {
        public object Data;
        public object Next;

        public TQueueNode()
            : this(null)
        {

        }
        public TQueueNode(object data)
        {
            this.Init(data);
        }

        public override void Initialize()
        {
            Init(null);
        }
        private void Init(object data)
        {
            this.Data = data;
            this.Next = null;
        }
    }  
    /// <summary>
    /// 无锁队列
    /// </summary>
    public class TQueue
    {
        private object _Head;
        private object _Tail;
        private long _Count;
        private EntityPool _NodePool = null;

        public long Count
        {
            get
            {
                return this._Count;
            }
        }

        public TQueue()
            : this(0)
        {
        }
        public TQueue(int nodeCount)
        {
            Init(nodeCount);
        }

        public void Enqueue(object item)
        {
            TQueueNode oldTail = null;
            TQueueNode oldTailNext = null;
            TQueueNode newNode = _NodePool.GetEntity() as TQueueNode;

            newNode.Data = item;

            do
            {
                oldTail = this._Tail as TQueueNode;
                oldTailNext = oldTail.Next as TQueueNode;

                if (oldTail == this._Tail)
                {
                    if (oldTailNext == null)
                    {
                        if (Interlocked.CompareExchange(ref oldTail.Next, newNode, oldTailNext) == oldTailNext)
                        {
                            break;
                        }
                    }
                    else
                    {
                        Interlocked.CompareExchange(ref this._Tail, oldTailNext, oldTail);
                    }
                }
            } while (true);

            Interlocked.CompareExchange(ref  this._Tail, newNode, oldTail);
            Interlocked.Increment(ref this._Count);
        }
        public object Dequeue(ref bool empty)
        {
            object result = null;
            TQueueNode tempTail = null;
            TQueueNode tempHead = null;
            TQueueNode tempHeadNext = null;

            do
            {
                tempHead = this._Head as TQueueNode;
                tempHeadNext = tempHead.Next as TQueueNode;
                tempTail = this._Tail as TQueueNode;

                if (tempHead == this._Head)
                {
                    if (tempHeadNext == null)
                    {
                        empty = true;
                        return null;
                    }
                    else
                    {
                        Interlocked.CompareExchange(ref this._Tail, tempHeadNext, tempTail);
                    }
                }
                else
                {
                    if (Interlocked.CompareExchange(ref this._Head, tempHeadNext, tempHead) == tempHead)
                    {
                        result = tempHeadNext.Data;
                        break;
                    }
                }
            } while (true);

            Interlocked.Decrement(ref this._Count);
            tempHead.Data = null;
            this._NodePool.Add(tempHead);
            return result;
        }
        public void Clear()
        {
            this.Init(0);
        }
        public void Clear(int nodeCount)
        {
            this.Init(nodeCount);
        }


        private void Init(int nodeCount)
        {
            System.Threading.Interlocked.Exchange(ref this._Count, 0);

            if (this._NodePool == null)
            {
                this._NodePool = new EntityPool(new TQueueNodeFactory(), true, nodeCount);
            }
            else
            {
                _NodePool.Clear(nodeCount);
            }
            this._Head = this._Tail = this._NodePool.GetEntity();
        }
    }

    public class TQueueNodeFactory : TEntityFactory
    {
        public override TEntity CreateTEntiy()
        {
            return new TQueueNode();
        }
    }
}